/*
 * @Author: xuetao 3168581151@qq.com
 * @Date: 2025-02-17
 * @LastEditors: xuetao 3168581151@qq.com
 * @LastEditTime: 2025-03-16
 * @Description: 
 */

import 'dart:async' show Timer;

import 'package:chat_client/config/api_config.dart';
import 'package:chat_client/config/socket_config.dart';
import 'package:chat_client/services/api_service.dart';
import 'package:chat_client/utils/show_messae.dart' show popError;
import 'package:socket_io_client/socket_io_client.dart' as io;
import 'package:chat_client/repositories/auth_repository.dart';

class SocketService {
  // 单例
  SocketService._internal();
  static final SocketService _instance = SocketService._internal();
  static SocketService get instance => _instance;

  final AuthRepository authRepository = AuthRepository.instance;
  final ApiService _apiService = ApiService.instance;

  late io.Socket _socket;
  // 后端服务器的 WebSocket URL
  final String _url = AppConfig.baseUrl;

  // 缓存消息队列
  final List<CacheEvent> _messageQueue = [];

  Timer? _heartbeatTimer;
  Timer? _pongCheckTimer;
  DateTime? _lastPongTime;

  // 检查是否已连接
  bool get isConnected => _socket.connected;

  io.Socket get socket => _socket;

  // 初始化 Socket.IO 连接
  void initSocket(
    void Function() addEventListener,
    void Function({required bool netState}) switchNetwork,
  ) {
    // 获取本地存储的 token
    final token = authRepository.accessToken;

    _socket = io.io(
      _url,
      io.OptionBuilder()
          .setTransports(['websocket']) // 使用 WebSocket 作为传输协议
          .setQuery({'token': token}) // 关键配置
          .enableReconnection() // 启用自动重连
          .setReconnectionAttempts(5) // 最大重连次数
          .setReconnectionDelay(1000) // 初始延迟 1 秒
          .setReconnectionDelayMax(5000) // 最大延迟 30 秒（指数退避）
          .build(),
    );

    // 监听连接事件
    _socket.on('connect', (_) async {
      if (_socket.recovered) {
        print("socket 链接恢复成功");
      } else {
        print("全新socket会话");
      }

      // 1. 注册心跳检测
      _startHearbeat();

      // 2.注册监听器
      addEventListener();

      // 3.检查并发送缓存
      _sendCacheQueue();

      // 5. 设置网络为已连接
      switchNetwork(netState: true);
    });

    // 重连监听
    _socket.on('reconnect_attempt', (_) {
      _socket.io.options?['query'] = {'token': authRepository.accessToken};
    });

    // 监听断开连接事件
    _socket.on('disconnect', (_) {
      print('链接断开');
      _disconnect();

      //设置网络为已断开
      switchNetwork(netState: true);
    });

    _socket.on('exception', (data) {
      print('websocket 错误： $data');
      throw WsError(message: data);
    });
  }

  // 触发事件
  void emitEvent({required String eventName, dynamic data}) {
    if (isConnected) {
      _socket.emit(eventName, data);
    } else {
      // 断网时缓存未发送消息
      _messageQueue.add(CacheEvent(event: eventName, data: data));
    }
  }

  // 注册事件监听器
  void addEventListener(String eventName, Function(dynamic data) callback) {
    if (isConnected) {
      // 移除旧监听器（如果存在）
      _socket.off(eventName);
      _socket.on(eventName, (data) {
        if (data is List<dynamic>) {
          callback(data[0]);
        } else {
          popError('socket 错误', '请检查socket消息类型');
        }
        print('检查 $eventName 消息 -: $data');
      });
      print('注册事件监听器: $eventName');
    } else {
      print('socket未连接');
    }
  }

  // 发送缓存信息
  void _sendCacheQueue() {
    for (var msg in _messageQueue) {
      _socket.emit(msg.event, msg.data);
    }
    _messageQueue.clear();
  }

  // 开启心跳ping
  void _startHearbeat() {
    const interval = Duration(seconds: 25); // 发送心跳间隔

    // 1. 定期发送心跳包
    _heartbeatTimer = Timer.periodic(interval, (_) {
      _socket.emit('ping', DateTime.now().millisecondsSinceEpoch);
    });

    // 2. 监听服务端响应
    addEventListener('pong', (data) {
      _lastPongTime = DateTime.now();
    });

    // 3. 启动心跳检测
    _startPongChecker();
  }

  void _startPongChecker() {
    const timeout = Duration(seconds: 30); // 超时判定时间

    _pongCheckTimer = Timer.periodic(timeout, (_) {
      if (_lastPongTime == null ||
          DateTime.now().difference(_lastPongTime!) > timeout) {
        print('心跳超时，尝试重连...');
        _socket.disconnect();
        _socket.connect();
      }
    });
  }

  // 在断开连接时清理资源
  void _disconnect() {
    _heartbeatTimer?.cancel();
    _pongCheckTimer?.cancel();
    _socket.disconnect();
  }
}

// 自定义错误类型，用于处理服务端返回的响应体错误
class WsError implements Exception {
  final String message;

  WsError({required this.message});

  @override
  String toString() {
    return message;
  }
}
